
#include "bitstream.h"

unsigned int rle8_encode_length(unsigned char *iptr,unsigned int ilen)
{
    struct bitstream bst;
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned char step = 0;//0:get first data,1:get second data and compare/store
    unsigned char v;
    unsigned char n;

    bitstream_init(&bst,iptr,ilen);
    ilen *= 8;
    for(i=0;i<ilen;i++)
    {
        if(step==0)
        {
            v = bitstream_read(&bst);
            n = 0;
            step++;
        }
        else
        {
            if(bitstream_read(&bst) == v)
            {
                n++;
                if(n >= 127)
                {
                    j++;
                    step = 0;
                }
            }
            else
            {
                j++;
                v = !v;
                n = 0;
            }                
        }
    }
    if(step > 0)
    {
        j++;
    }
    return j;
}
unsigned int rle8_encode(unsigned char *iptr,unsigned int ilen,unsigned char *optr,unsigned int olen)
{
    struct bitstream bst;
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned char step = 0;//0:get first data,1:get second data and compare/store
    unsigned char v;
    unsigned char n;

    bitstream_init(&bst,iptr,ilen);
    ilen *= 8;
    if((ilen > 0) && (olen > 0))
    {
        for(i=0;i<ilen;i++)
        {
            if(step == 0)
            {
                v = bitstream_read(&bst);
                n = 0;
                step++;
            }
            else
            {
                if(bitstream_read(&bst) == v)
                {
                    n++;
                    if(n >= 127)
                    {
                        optr[j++] = (v<<7)|n;
                        step = 0;
                        if(j >= olen)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    optr[j++] = (v<<7)|n;
                    if(j < olen)
                    {
                        v = !v;
                        n = 0;
                    }
                    else
                    {
                        break;
                    }
                }
            }

        }
        if(step > 0)
        {
            if(j < olen)
            {
                optr[j++] = (v<<7)|n;
            }
        }
    }
    return j;
}
unsigned int rle8_decode_length(unsigned char *iptr,unsigned int ilen)
{
    unsigned int n = 0;

    for(int i=0;i<ilen;i++)
    {
        n += (iptr[i]&0x7f) + 1;
    }
    return n/8 + (n%8?1:0);
}
unsigned int rle8_decode(unsigned char *iptr,unsigned int ilen,unsigned char *optr,unsigned int olen)
{
    struct bitstream bst;
    unsigned int len = 0;
    unsigned int n;
    unsigned char v;

    bitstream_init(&bst,optr,olen);
    for(int i=0;i<ilen;i++)
    {
        v = iptr[i]&0x80 ? 1 : 0;
        n = (iptr[i]&0x7f) + 1;
        for(int j=0;j<n;j++)
        {
            bitstream_write(&bst, v);
        }
        len += n;
    }
    return len/8;
}



unsigned int rle4_encode_length(unsigned char *iptr,unsigned int ilen)
{
    struct bitstream src;
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned char step = 0;//0:get first data,1:get second data and compare/store
    unsigned char v;
    unsigned char n;

    bitstream_init(&src,iptr,ilen);
    ilen *= 8;
    if(ilen > 0)
    {
        for(i=0;i<ilen;i++)
        {
            if(step == 0)
            {
                v = bitstream_read(&src);
                n = 0;
                step++;
            }
            else
            {
                if(bitstream_read(&src) == v)
                {
                    n++;
                    if(n >= 7)
                    {
                        step = 0;
                        j++;
                    }
                }
                else
                {
                    j++;
                    v = !v;
                    n = 0;
                }
            }
        }
        if(step > 0)
        {
            j++;
        }
    }
    return j/2 + (j%2 ? 1 : 0);
}
unsigned int rle4_encode(unsigned char *iptr,unsigned int ilen,unsigned char *optr,unsigned int olen)
{
    struct bitstream src;
    struct bitstream dst;
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned char step = 0;//0:get first data,1:get second data and compare/store
    unsigned char v;
    unsigned char n;

    bitstream_init(&src,iptr,ilen);
    bitstream_init(&dst,optr,olen);
    ilen *= 8;
    olen *= 2;
    if((ilen > 0) && (olen > 0))
    {
        for(i=0;i<ilen;i++)
        {
            if(step == 0)
            {
                v = bitstream_read(&src);
                n = 0;
                step++;
            }
            else
            {
                if(bitstream_read(&src) == v)
                {
                    n++;
                    if(n >= 7)
                    {
                        bitstream_write(&dst,v);
                        bitstream_write(&dst,(n>>2)&1);
                        bitstream_write(&dst,(n>>1)&1);
                        bitstream_write(&dst,(n&1));
                        step = 0;
                        j++;
                        if(j >= olen)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    bitstream_write(&dst,v);
                    bitstream_write(&dst,(n>>2)&1);
                    bitstream_write(&dst,(n>>1)&1);
                    bitstream_write(&dst,(n&1));
                    j++;
                    if(j < olen)
                    {
                        v = !v;
                        n = 0;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
        if(step > 0)
        {
            if(j < olen)
            {
                bitstream_write(&dst,v);
                bitstream_write(&dst,(n>>2)&1);
                bitstream_write(&dst,(n>>1)&1);
                bitstream_write(&dst,(n&1));
                j++;
            }
        }
    }
    return j/2 + (j%2 ? 1 : 0);
}
unsigned int rle4_decode_length(unsigned char *iptr,unsigned int ilen)
{
    unsigned int n = 0;

    for(int i=0;i<ilen;i++)
    {
        n += (iptr[i]&0x7) + ((iptr[i]>>4)&0x7) + 2;
    }
    return n/8 + (n%8?1:0);
}
unsigned int rle4_decode(unsigned char *iptr,unsigned int ilen,unsigned char *optr,unsigned int olen)
{
    struct bitstream bst;
    unsigned int len = 0;
    unsigned int n;
    unsigned char v;

    bitstream_init(&bst,optr,olen);
    for(int i=0;i<ilen;i++)
    {
        //high 4 bit
        v = iptr[i]&0x80 ? 1 : 0;
        n = ((iptr[i]>>4)&0x07) + 1;
        for(int j=0;j<n;j++)
        {
            bitstream_write(&bst, v);
        }

        //low 4 bit
        v = iptr[i]&0x08 ? 1 : 0;
        n = (iptr[i]&0x07) + 1;
        for(int j=0;j<n;j++)
        {
            bitstream_write(&bst, v);
        }
        len += n;
    }
    return len/8;
}